// pages/mall/chat/chat.js
import { getElementDs, openAuth,getRandom,formatDateString } from "../../../../utils/util"
import * as Storage from "../../../../utils/storage"
import Toast from '../../../../miniprogram_npm/@vant/weapp/toast/toast';
const $api = require('../../../../request/api').API;
const app = getApp()
const recorderManager = wx.getRecorderManager()
const innerAudioContext = wx.createInnerAudioContext()
const animation = wx.createAnimation()
const URL = $api.env == "pro" ? 'https://kicc-gateway.kanglailab.com/' : 'http://192.168.3.10:9999/'

const options = {
  duration: 20000,//指定录音的时长，单位 ms
  sampleRate: 16000,//采样率
  numberOfChannels: 1,//录音通道数
  encodeBitRate: 96000,//编码码率
  format: 'mp3',//音频格式，有效值 aac/mp3
  frameSize: 50,//指定帧大小，单位 KB
}
Page({

  /**
   * 页面的初始数据
   */
  data: {
    avatarUrl:"",//本地存储的头像
    contentHeight: 0,//对话框高度
    bottomHeight: 0, //底部高度，用的rpx
    inputHeight: 0,//输入框高度
    statusBarHeight: 50,//状态栏发哦都
    isText: true,//为true表示文字为false表示语音
    inputValue: "",//输入的值
    recordObj:{},//包含录音的对象
    focus: false,//是否获取焦点
    msgList: [],
    isPlay: false,// 是否正在播放
    // itemIndex: -1,//正在播放的索引
    animation: null,
    // resetIndex: -1,//重置动画的索引
    reset:false,//是否充值动画
    resetAnimation: null,//重置动画
    tempId:"",//正在播放的语音id
    showRecord: false,
    scrollId: "",//每次录音结束或者发送消息结束都需要滚动到底部
    refreshState: true,//刷新状态
    finishPage:false,//是否已经最后一页
    page: {
      pageSize: 2,//一页的个数
      // pageNo: 1,//第几页
      // totalPage: 1,//总页数
      // total:2,//总数
    },
    cursor:"",//请求列表的时候后端会返回这个，后端返回来，下一才就发过去
    receiveUserId: "1725324480014442498",
    kiccUserId: "",
    sessionId:"",
    closeRecord:false,// true表示关闭录音，false表示录音
    contextEnable:false, //false表示新的会话
  },

  /**
   * 生命周期函数--监听页面加载
   */
  async onLoad(options) {
    // 已经来就判断是否授权过如果没有授权
    wx.getSetting({
      success: res => {
        this.authRecord = res.authSetting['scope.record']
      }
    })
    this.setData({
      avatarUrl:wx.getStorageSync('avatarUrl')
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {
    this.getStyle()
    this.init()
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {
    // if (!this.flag) {
    //   this.flag = true
    //   this.getStyle()
    // }
  },
  async init() {
    this.watch()
    try{
      Toast.loading({
        forbidClick:true,
        mask:true,
        message:"加载数据中",
        duration:0
      })
      const res = await $api.getUserByCasUserld(wx.getStorageSync(Storage.CAS_USER_ID))
      this.setData({
        kiccUserId: res.data.data.id
      })
      await this.existOldChat()
      await this.getList()
    }finally{
      Toast.clear()
    }
    
  },
  // 初始话动态样式
  async getStyle() {
    const { safeArea, statusBarHeight, windowHeight,screenHeight,system } = wx.getSystemInfoSync()
    console.log(system)
    // windowHeight之外的顶部导航高度
    wx.nextTick(async () => {
      const res = await getElementDs([".bottom", ".input"])
      this.setData({
        contentHeight:windowHeight-res[0].height,
        inputHeight: res[1].height+'px'
      })
    })
  },
  // 监听录音和播放
  watch() {
    // 监听开始录音
    recorderManager.onStart(e => {
      if (this.end) recorderManager.stop()
      this.setData({
        showRecord: true
      },()=>{
        // 录音开始的时候获取上面两个选项关闭、新会话的位置
        if(!this.poistions||!this.poistions[0]) this.getNodePosition()
      })

    })
    // 监听结束录音
    recorderManager.onStop(async e => {
      let { duration, tempFilePath } = e
      let {kiccUserId,closeRecord,contextEnable } = this.data
      this.setData({
        showRecord: false,
      })
      // type为0表示关闭录音
      if(closeRecord){
        this.setData({
          closeRecord:false
        })
        return
      } 

      if (duration < 1000) {
        return wx.showToast({
          title: '录音时间太短',
          icon: "error"
        })
      }
      duration = Math.ceil(duration / 1000)
      // 临时存储录音对象
      const recordObj = {
        id:getRandom(),
        duration,
        content: "",
        availablePath: tempFilePath,
        contentType: "1",
        sendUserId:kiccUserId,
        revert:contextEnable?"0":"1",
        sendTime:formatDateString(new Date(),"yyyy-MM-dd HH:mm:ss")
      }

      this.setData({
        recordObj,
      })
      this.addMsg(recordObj)
      this.getData()
      
    })

    // 监听开始播放
    innerAudioContext.onPlay(async e => {
      try {
        clearTimeout(this.innerPlayTimer)
        clearInterval(this.playTimer)
        this.playTimer = setInterval(async () => {
          await this.handlePlayAnimation('14rpx', '14rpx')
          await this.handlePlayAnimation('23rpx', '24rpx', 300)
          await this.handlePlayAnimation('50rpx', '50rpx', 300)
        }, 1400)
        await this.handlePlayAnimation('14rpx', '14rpx')
        await this.handlePlayAnimation('23rpx', '24rpx', 300)
        await this.handlePlayAnimation('50rpx', '50rpx', 300)
      } catch {
        clearTimeout(this.innerPlayTimer)
        clearInterval(this.playTimer)
      }
      this.setData({
        isPlay: true,
      })
    })
    // 监听暂停播放
    innerAudioContext.onStop(async (e) => {
      this.setData({
        isPlay: false,
      })
    })
    // 监听自动结束播放
    innerAudioContext.onEnded(e => {
      clearTimeout(this.innerPlayTimer)
      clearInterval(this.playTimer)
      this.setData({
        isPlay: false,
        reset:true,
        resetAnimation: animation.width('50rpx').height("56rpx").step({ duration: 1 }).export()
      })
    })
  },
  // 判断是否有旧的会话
  async existOldChat(){
    let res = await $api.lastSession({userId:this.data.kiccUserId})
    const sessionId = wx.getStorageSync('sessionId')
    if(!res.data.data||!sessionId){
      // 如果不存在新的会话就需要开启新的会话
      this.newChat(true)
    }else if(sessionId){
      this.setData({
        sessionId
      })
    }
  },
  // 开启新的会话
  async newChat(flag = false){
    const {kiccUserId,receiveUserId} = this.data
    try{
      if(!flag) this.permForbidRequest(true) 
      let res = await $api.sessionSave({userId:kiccUserId,receiveUserId})
      const {id} = res.data.data
      this.setData({
        sessionId:id
      })
      wx.setStorageSync('sessionId',id)
    }catch{
      this.permForbidRequest(false)
    }
  },
  // 获取消息列表
  async getList() {
    const { page, kiccUserId, receiveUserId, msgList,cursor } = this.data
    const { pageSize } = page
    const params = {
      sendUserId: kiccUserId,
      receiveUserId,
      // current: pageNo,
      size: pageSize,
      cursor,

    }
    try {
      const res = await $api.chatMessage(params)
      const { data,cursor } = res.data.data
      // page.totalPage = total === 0 ? 0 : Math.ceil(total / pageSize)
      const finishPage = data.length?false:true//表示是否是最后一页结束了
      // page.total = total
      data.reverse()
      this.setData({
        msgList: data.concat(msgList),
        page,
        refreshState: true,
        finishPage,
        cursor
      })

      // 如果cursor不存在的话就表示是最新一页的数据需要滚动到底部
      if (!cursor&&data.length) {
        wx.nextTick(() => {
          this.setData({
            scrollId: "a" + this.data.msgList.length,
          })
        })
      }
    } finally {
      this.setData({
        refreshState: false
      })
    }

  },
  /**
   * 获取回复消息
   * @param contentEnable true表示新的会话 false表示继续发送
   * 
   */
  async getData() {
    const { inputValue, recordObj:{availablePath}, kiccUserId, receiveUserId,isText,sessionId,msgList,contextEnable } = this.data
    this.setData({
      selectType:""
    })
    this.permForbidRequest(true)
    try {
      let res = null
      let params = {
        sendUserId: kiccUserId,
        receiveUserId,
        content:inputValue,
        contentType:"0",
        sessionId,
        revert:"0"
      }
      
      // 这个字段用来表示是否显示事件
      let revert = "0"
      if(!contextEnable){
        // contextEnable为false表示新的会话
        await this.newChat()
        params.revert = "1"
      }else if(!msgList.length){
        // 如果消息列表数据为空那么也需要添加一个记录
        params.revert = "1"
      } 

      if(isText) {
        res = await $api.chatCompletions(params)
        this.addMsg(res.data.data)
      } else{ 
        // 语音转文字
        params.contentType = "1"
        res = await $api.transcriptions(availablePath,params)
        res = res.data
        console.log(res,"语音转文字")

        // 发送文字
        params.content = res.content
        params.files = res.files
        // revert&&(params.revert = revert)
        res = await $api.chatCompletions(params)
        console.log(res,"发送文字")
        res = res.data.data
        const id = res.id
        params.id = id
        params.content = res.content

        // 文字转语音
        res = await $api.speech(params)
        console.log(res,"文字转语音")
        this.addMsg({...res.data.data,contentType:"1",id})
      }
    } finally {
     this.permForbidRequest(false)
     this.setData({
      contextEnable:false
     })
    }
  },
  /**
   * 禁止请求或者允许请求
   * @param bool -为true表示请求中不可以再次请求 为false表示没有处于请求中可以请求
   */ 
  permForbidRequest(bool){
    this.waitingRequest = bool
    wx.setNavigationBarTitle({
      title: bool?"回复中...":'聊天'
    })
  },
  // 切换文字或者录音
  switchType(e) {
    const isText = e.currentTarget.dataset.type
    this.setData({
      isText,
      focus: isText ? true : false
    })
  },
  // 是否继续发送 
  changeContextEnable(e){
    this.setData({
      contextEnable:!this.data.contextEnable
    })
  },
  // 输入
  handleInput(e) {
    this.setData({
      inputValue: e.detail.value
    })
  },
  /**
   * 发送消息
   * type 1表示普通发送消息 2表示更多 3表示新的会话
   */ 
  async sendMsg(e) {
    if (this.waitingRequest) {
      return wx.showToast({
        title: '不要发送太频繁',
        icon: "error"
      })
    }
    let { inputValue, kiccUserId,contentEnable } = this.data
    // let {type} = e.currentTarget.dataset
    // 需要输入内容
    if (!inputValue) return
    const obj = {
      availablePath: null,
      contentType: "0",
      sendUserId: kiccUserId,
      content: inputValue,
      revert:contentEnable?"0":"1",
      sendTime:formatDateString(new Date(),"yyyy-MM-dd HH:mm:ss")
    }
    this.addMsg(obj)
    this.getData()
  },
  // 添加一条消息
  addMsg(obj) {
    const { msgList,contextEnable } = this.data
    // 这里如果obj里面不存在id的话就添加一个随机id
    !obj.id&&(obj.id = getRandom())
    // 不存在消息就添加一个时间
    if(!msgList.length)obj.revert = "1"
    msgList.push(obj)
    this.setData({
      msgList,
      scrollId: "a" + msgList.length
    })

    // 清空发送内容
    if (!obj.availablePath) {
      wx.nextTick(() => {
        this.setData({
          inputValue: ""
        })
      })
    }
  },
  // 开始录音
  async recordSoundStart(e) {
    if (this.waitingRequest) {
      return wx.showToast({
        title: '不要发送太频繁',
        icon: "error"
      })
    }
     /**
     * 这个this.end用来处理bug，有一种情况是快速触屏结束这个时候还没开始录音就触发了结束
     * 也就是先执行recorderManager.end然后再执行reocrderManager.start，这个时候录音就结束不了了所以
     * 在reocrderManager.onStart的回调里面需要用this.end来判断是否结束
     */
    this.end = false
    // 判断是否授权，两种情况：没有授权过或者取消过授权
    try {
      if (this.authRecord === undefined) {
        await wx.authorize({ scope: 'scope.record' })
        return this.authRecord = true
      } else if (!this.authRecord) {
        wx.showModal({
          title: '提示',
          content: '暂未语音授权，是否去授权',
          success: async res => {
            if (res.confirm) {
              this.authRecord = await openAuth("scope.record")
            }
          }
        })
        return
      }
      wx.vibrateLong()
      recorderManager.start(options)
    } catch {
      this.authRecord = false
    }

  },
  // 录音的时候获取关闭和新会话的位置
  async getNodePosition(){
    const res = await getElementDs([".select-cancel"])
    this.poistions = res
  },
  // 判断在结束触屏的时候手指停留在哪个区域
  getCurrentPosition({changedTouches:[{clientX,clientY}]}){
     const index =  this.poistions.findIndex(item=>{
      return item.top<clientY&&item.bottom>clientY&&item.left<clientX&&item.right>clientX
    })
    // closeRecord: true表示按到关闭录音上面了，false才是正常录音

    this.setData({
      closeRecord:index==-1?false:true
    })
  },
  // 录音的时候手指移动触屏
  async recordSoundMove(e){
    // 避免移动过快，使用moveTime来控制ss
    if(this.moveTime) return
    if(!this.poistions) return
    this.getCurrentPosition(e)
    this.moveTime = true
    setTimeout(()=>{
      this.moveTime = false
    },200)
  },
  // 结束录音
  recordSoundEnd(e) {
    this.end = true
    this.setData({
      showRecord: false
    })
    this.getCurrentPosition(e)
    recorderManager.stop()
  },
  // 播放录音或者停止播放
  async clickPlaySound(e) {
    // this.clickPlayTimer 用来控制不能反复点击
    if (this.clickPlayTimer) return
    this.clickPlayTimer = true
    setTimeout(() => {
      this.clickPlayTimer = false
    }, 100)
    let { isPlay,tempId, } = this.data
    let { availablePath,id} = e.currentTarget.dataset.item
    if (!availablePath) return
    
    if (isPlay && id == tempId) {
      // 再次点击已经在播放的录音就停止
      clearTimeout(this.innerPlayTimer)
      clearInterval(this.playTimer)
      this.setData({
        reset:true,
        resetAnimation: animation.width('50rpx').height("56rpx").step({ duration: 1 }).export()
      })
      innerAudioContext.stop()
      return
    } else if (isPlay && id !== tempId) {
      // 点击另一条语音，这个时候会停止正在播放的语音，需要重置动画，微信小程序动画有bug不能重置
      this.setData({
        reset:true,
        resetAnimation: animation.width('50rpx').height("56rpx").step({ duration: 1 }).export()
      })
    }
    this.setData({
      tempId:id,
      reset:false,
    })
    innerAudioContext.src = availablePath
    // "http://m10.music.126.net/20231120170721/2d4349f3ea45a0887e8e92de8765a893/ymusic/5353/0f0f/0358/d99739615f8e5153d77042092f07fd77.mp3"
    innerAudioContext.play()
  },
  // 播放定时器
  handlePlayAnimation(width, height, delay = 1) {
    return new Promise((resolve, reject) => {
      this.innerPlayTimer = setTimeout(() => {
        this.setData({
          animation: animation.width(width).height(height).step({ duration: 1 }).export(),
        }, () => {
          resolve()
        })
      }, delay)
    })
  },
  // 刷新获取数据
  async refresh(e) {
    // const { page:{total},msgList } = this.data
    if(this.data.finishPage){
      this.setData({
        refreshState: false
      })
      return
    } 
    // const { total, pageNo } = page
    // if (msgList.length == total) {
    //   this.setData({
    //     refreshState: false
    //   })
    //   return
    // }
    // page.pageNo++
    // this.setData({
    //   page
    // })
    await this.getList()

  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {
    innerAudioContext.stop()
  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {

  }
})